﻿using System;
using System.Text;
using System.Xml.Serialization;
using System.Collections.Generic;

namespace Spacer {
	[XmlRoot("packet")]
	public class Packet : IXmlSerializable {
		public Packet() {}

		public Packet( string name, object data ) {
			Name = name;
			Data = data;
		}

		// ----------

		#region IXmlSerializable Members
		public System.Xml.Schema.XmlSchema GetSchema() {
			return null;
		}

		public void ReadXml( System.Xml.XmlReader reader ) {
			XmlSerializer nameSerializer;
			XmlSerializer dataSerializer;

			bool wasEmpty = reader.IsEmptyElement;
			reader.Read();

			if( wasEmpty )
				return;
			
			if( !s_Serializers.TryGetValue(typeof(string),out nameSerializer) )
				nameSerializer = s_Serializers[typeof(string)] = new XmlSerializer( typeof(string) );

			reader.ReadStartElement( "name" );
			Name = (string)nameSerializer.Deserialize( reader );
			reader.ReadEndElement();

			reader.ReadToFollowing( "data" );
				Type type;
				if( reader.HasAttributes ) {
					String attr = reader.GetAttribute( "type" );
					type = Type.GetType( attr );
				} else {
					throw new Exception( "Type not found!" );
				}
			reader.ReadStartElement( "data" );
				if( !s_Serializers.TryGetValue(type,out dataSerializer) )
					dataSerializer = s_Serializers[type] = new XmlSerializer( type );
				Data = dataSerializer.Deserialize( reader );
			reader.ReadEndElement();

			reader.ReadEndElement();
			reader.MoveToContent();
		}

		public void WriteXml( System.Xml.XmlWriter writer ) {
			XmlSerializer nameSerializer;
			XmlSerializer dataSerializer;
			
			if( !s_Serializers.TryGetValue(typeof(string),out nameSerializer) )
				nameSerializer = s_Serializers[typeof(string)] = new XmlSerializer( typeof(string) );

			writer.WriteStartElement( "name" );
			nameSerializer.Serialize( writer, Name );
			writer.WriteEndElement();

			writer.WriteStartElement( "data" );
				Type type = Data.GetType();
				writer.WriteAttributeString( "type", type.AssemblyQualifiedName );

				if( !s_Serializers.TryGetValue(type,out dataSerializer) )
					dataSerializer = s_Serializers[type] = new XmlSerializer( type );
				dataSerializer.Serialize( writer, Data );
			writer.WriteEndElement();
		}
		#endregion

		public string Serialize() {
			return XmlObjectCfg<Packet>.SerializeToString( this );
		}

		public static string Serialize( string name, object data ) {
			return XmlObjectCfg<Packet>.SerializeToString( new Packet(name,data) );
		}

		public static Packet Deserialize( string xml ) {
			return XmlObjectCfg<Packet>.DeserializeFromString( xml );
		}

		// ----------

		private static Dictionary<Type,XmlSerializer> s_Serializers = new Dictionary<Type,XmlSerializer>();

		public string Name { get; set; }
		public object Data { get; set; }
	}
}